﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Algorithm.Check;
using Common;
using static Algorithm.Check.ExtensionForCRC16;

namespace NewDevice.RS485
{
    /// <summary>
    /// 30V40A程控电源
    /// </summary>
    [Obsolete("该类已弃用，请使用 RU_12_3040_V2 替代")]
    public class RU_12_3040
    {
        /// <summary>
        /// 设备名称
        /// </summary>
        private string deviceName = "RU12-3040程控电源";

        /// <summary>
        /// 串口通信对象
        /// </summary>
        private readonly SerialBase serial;

        private readonly int slaveId;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="bus"></param>
        /// <param name="slaveId"></param>
        /// <param name="devName"></param>
        public RU_12_3040(SerialBase bus, int slaveId, string devName = "RU12-3040程控电源")
        {
            this.serial = bus;
            this.slaveId = slaveId;
            deviceName = devName;
        }

        /// <summary>
        /// 设置输出电压
        /// </summary>
        /// <param name="vol">电压值(单位：V)</param>
        /// <exception cref="Exception">当设置失败或返回数据异常时抛出</exception>
        public void SetVoltage(double vol)
        {
            int volSet = (int)(vol * 100);
            Mylog.Info(deviceName: deviceName, message: $"从机[{slaveId}]设置电压[{vol}]");
            byte[] data = new byte[] {
             (byte)slaveId,
             0x06, // 功能码:写单个寄存器
             0x00, 0x95, // 寄存器地址:0x0095(输出电压设置寄存器)
             (byte)((volSet & 0xff00) >> 8), // 电压值高字节
             (byte)(volSet & 0xff), // 电压值低字节
            };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            serial.deviceName = deviceName;
            var recv = serial.SendBytesAndWaitResponse(cmd, ReceivedDataCheck.FuncModbusCRC16Check);
            if (!recv.SequenceEqual(cmd))
            {
                throw new Exception($"{deviceName} SetVoltage 返回数据异常");
            }
        }

        /// <summary>
        /// 读取当前输出电压
        /// </summary>
        /// <returns>当前输出电压值(单位：V)</returns>
        /// <exception cref="Exception">当读取失败或返回数据异常时抛出</exception>
        public double GetVoltage()
        {
            byte[] data = new byte[] {
             (byte)slaveId,
             0x03, // 功能码:读保持寄存器
             0x00, 0x95, // 寄存器地址:0x0095(输出电压读取寄存器)
             0x00, 0x01 // 读取寄存器数量:1
         };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            serial.deviceName = deviceName;
            var recv = serial.SendBytesAndWaitResponse(cmd, ReceivedDataCheck.FuncModbusCRC16Check);
            if (recv.Length != 7)
            {
                throw new Exception($"{deviceName} GetVoltage 返回数据异常");
            }
            var vol = ((recv[3] & 0xFF) << 8) | (recv[4] & 0xFF);
            Mylog.Info(deviceName: deviceName, message: $"从机[{slaveId}]读取电压[{vol / 100.0}]");
            return vol / 100.0;
        }

        /// <summary>
        /// 设置输出电流
        /// </summary>
        /// <param name="current">电流值(单位：A)</param>
        /// <exception cref="Exception">当设置失败或返回数据异常时抛出</exception>
        public void SetCurrent(double current)
        {
            Mylog.Info(deviceName: deviceName, message: $"从机[{slaveId}]设置电流[{current}]");
            int tmp = (int)(current * 100); // 转换为mA单位
            byte[] data = new byte[] {
             (byte)slaveId,
             0x06, // 功能码:写单个寄存器
             0x00, 0x96, // 寄存器地址:0x0096(输出电流设置寄存器)
             (byte)((tmp & 0xff00) >> 8), // 电流值高字节
             (byte)(tmp & 0xff), // 电流值低字节
         };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            serial.deviceName = deviceName;
            var recv = serial.SendBytesAndWaitResponse(cmd, ReceivedDataCheck.FuncModbusCRC16Check);
            if (!recv.SequenceEqual(cmd))
            {
                throw new Exception($"{deviceName} SetCurrent 返回数据异常");
            }
        }

        /// <summary>
        /// 读取当前输出电流
        /// </summary>
        /// <returns>当前输出电流值(单位：A)</returns>
        /// <exception cref="Exception">当读取失败或返回数据异常时抛出</exception>
        public double GetCurrent()
        {
            byte[] data = new byte[] {
             (byte)slaveId,
             0x03, // 功能码:读保持寄存器
             0x00, 0x96, // 寄存器地址:0x0096(输出电流读取寄存器)
             0x00, 0x01 // 读取寄存器数量:1
         };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            serial.deviceName = deviceName;
            var recv = serial.SendBytesAndWaitResponse(cmd, ReceivedDataCheck.FuncModbusCRC16Check);
            if (recv.Length != 7)
            {
                throw new Exception($"{deviceName} GetCurrent 返回数据异常");
            }
            var cur = (double)(((recv[3] & 0xFF) << 8) | (recv[4] & 0xFF)) / 100; // 转换为A单位
            Mylog.Info(deviceName: deviceName, message: $"从机[{slaveId}]读取电流[{cur}]");
            return cur;
        }

        /// <summary>
        /// 测量输出电流
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public double MeasCurrent()
        {
            byte[] data = new byte[] {
             (byte)slaveId,
             0x04, // 功能码:读保持寄存器
             0x00, 0x65, // 寄存器地址:0x0096(输出电流读取寄存器)
             0x00, 0x01 // 读取寄存器数量:1
         };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            serial.deviceName = deviceName;
            var recv = serial.SendBytesAndWaitResponse(cmd, ReceivedDataCheck.FuncModbusCRC16Check);
            if (recv.Length != 7)
            {
                throw new Exception($"{deviceName} GetCurrent 返回数据异常");
            }
            var cur = (double)(((recv[3] & 0xFF) << 8) | (recv[4] & 0xFF)) / 100; // 转换为A单位
            Mylog.Info(deviceName: deviceName, message: $"从机[{slaveId}]测量电流[{cur}]");
            return cur;
        }

        /// <summary>
        /// 测量输出电压
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public double MeasVoltage()
        {
            byte[] data = new byte[] {
             (byte)slaveId,
             0x04, // 功能码:读保持寄存器
             0x00, 0x64, // 寄存器地址:0x0096(输出电流读取寄存器)
             0x00, 0x01 // 读取寄存器数量:1
         };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            serial.deviceName = deviceName;
            var recv = serial.SendBytesAndWaitResponse(cmd, ReceivedDataCheck.FuncModbusCRC16Check);
            if (recv.Length != 7)
            {
                throw new Exception($"{deviceName} GetCurrent 返回数据异常");
            }
            var vol = (double)(((recv[3] & 0xFF) << 8) | (recv[4] & 0xFF)) / 100; // 转换为A单位
            Mylog.Info(deviceName: deviceName, message: $"从机[{slaveId}]测量电压[{vol}]");
            return vol;
        }

        /// <summary>
        /// 设置电源输出状态
        /// </summary>
        /// <param name="isOn">true:开启输出, false:关闭输出</param>
        /// <exception cref="Exception">当设置失败或返回数据异常时抛出</exception>
        public void SetStatus(bool isOn)
        {
            Mylog.Info(deviceName: deviceName, message: $"从机[{slaveId}]设置电源输出状态[{isOn}]");
            byte[] data = new byte[] {
             (byte)slaveId,
             0x05, // 功能码:写单个线圈
             0x00, 0x85, // 线圈地址:0x0085(输出控制寄存器)
             (byte)(isOn ? 0xff : 0x00), // 控制值
             0x00 // 填充字节
         };
            byte[] cmd = data.WithCRC16(CRC16Type.Modbus).ToArray();
            serial.deviceName = deviceName;
            var recv = serial.SendBytesAndWaitResponse(cmd, ReceivedDataCheck.FuncModbusCRC16Check);
            if (!recv.SequenceEqual(cmd))
            {
                throw new Exception($"{deviceName} SetStatus 返回数据异常");
            }
        }
    }
}